package org.softee.functional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public abstract class AbstractFunctionalIterable<T> implements FunctionalIterable<T> {
    protected final Iterable<T> iterable;

    protected AbstractFunctionalIterable(Iterable<T> iterable) {
        this.iterable = iterable;
    }

    @Override
    public Iterator<T> iterator() {
        return iterable.iterator();
    }

    @Override
    public boolean isEmpty() {
        return !iterator().hasNext();
    }

    @Override
    public <A extends Collection<? super T>> A into(A target) {
        for (T element : iterable) {
            target.add(element);
        }
        return target;
    }

    @Override
    public List<T> asList() {
        if (iterable instanceof List) {
            return (List<T>) iterable;
        }
        //TODO preallocate size
        return into(new ArrayList<T>());
    }

    @Override
    public T getAny() {
        // TODO according to JDK 8 javadocs, this may return other than first
        return getFirst();
    }

    @Override
    public T getFirst() {
        return iterator().next();
    }

    @Override
    public T getOnly() {
        Iterator<T> iterator = iterator();
        T only = iterator.next();
        if (iterator.hasNext()) {
            throw new IllegalStateException("Multiple elements");
        }
        return only;
    }

    @Override
    public String toString() {
        // return "[" + map(Mappers.stringValue()).reduce(null, join(", ")) + "]";

        StringBuilder sb = new StringBuilder(1000);
        sb.append("[");
        boolean first = true;
        for (Object element : this) {
            if (!first) {
                sb.append(", ");
            } else {
                first = false;
            }
            sb.append(element);
        }
        return sb.append("]").toString();
    }
}
